package com.ityuwen.mengyagushi.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.ityuwen.mengyagushi.account.client.UserAccountFeignClient;
import com.ityuwen.mengyagushi.album.client.AlbumInfoFeignClient;
import com.ityuwen.mengyagushi.album.client.TrackInfoFeignClient;
import com.ityuwen.mengyagushi.common.constant.KafkaConstant;
import com.ityuwen.mengyagushi.common.constant.RedisConstant;
import com.ityuwen.mengyagushi.common.constant.SystemConstant;
import com.ityuwen.mengyagushi.common.execption.GuiguException;
import com.ityuwen.mengyagushi.common.result.Result;
import com.ityuwen.mengyagushi.common.result.ResultCodeEnum;
import com.ityuwen.mengyagushi.common.service.KafkaService;
import com.ityuwen.mengyagushi.common.util.AuthContextHolder;
import com.ityuwen.mengyagushi.model.order.OrderDerate;
import com.ityuwen.mengyagushi.model.order.OrderDetail;
import com.ityuwen.mengyagushi.model.order.OrderInfo;
import com.ityuwen.mengyagushi.order.helper.SignHelper;
import com.ityuwen.mengyagushi.order.mapper.OrderDerateMapper;
import com.ityuwen.mengyagushi.order.mapper.OrderDetailMapper;
import com.ityuwen.mengyagushi.order.mapper.OrderInfoMapper;
import com.ityuwen.mengyagushi.order.service.OrderInfoService;
import com.ityuwen.mengyagushi.order.service.template.OrderConfirmTemplate;
import com.ityuwen.mengyagushi.user.client.UserInfoFeignClient;
import com.ityuwen.mengyagushi.user.client.VipServiceConfigFeignClient;
import com.ityuwen.mengyagushi.vo.account.AccountLockResultVo;
import com.ityuwen.mengyagushi.vo.account.AccountLockVo;
import com.ityuwen.mengyagushi.vo.order.OrderDerateVo;
import com.ityuwen.mengyagushi.vo.order.OrderDetailVo;
import com.ityuwen.mengyagushi.vo.order.OrderInfoVo;
import com.ityuwen.mengyagushi.vo.order.TradeVo;
import com.ityuwen.mengyagushi.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private OrderConfirmTemplate orderConfirmTemplate;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderDerateMapper derateMapper;

    @Autowired
    private KafkaService kafkaService;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo) {
        return orderConfirmTemplate.orderConfirm(tradeVo);
    }

    @Transactional
    @Override
    public void submitOrder(OrderInfoVo orderInfoVo) {
        // 1.验签
        HashMap hashMap = JSON.parseObject(JSON.toJSONString(orderInfoVo), HashMap.class);
        // 临时为了保证验签通过，把支付方式改回默认支付方式
        hashMap.put("payWay", SystemConstant.ORDER_PAY_WAY_WEIXIN);
        SignHelper.checkSign(hashMap);

        // 2.防重复提交  orderInfoVo有页面传递的tradeNo，到redis中查询，如果查到了说明没有重复提交则可以提交，立马把redis中的tradeNo删除
        String tradeNo = orderInfoVo.getTradeNo();
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                "then " +
                "   return redis.call('del', KEYS[1]) " +
                "else " +
                "   return 0 " +
                "end";
        Boolean flag = (Boolean)this.redisTemplate.execute(new DefaultRedisScript(script, Boolean.class), Arrays.asList(RedisConstant.ORDER_IDEM_PREFIX + tradeNo), tradeNo);
        if (!flag){
            throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
        }

        // 3.判断支付方式，如果是非余额支付则直接保存订单
        if (!SystemConstant.ORDER_PAY_WAY_ACCOUNT.equals(orderInfoVo.getPayWay())){
            this.saveOrder(orderInfoVo);
            // TODO：非余额支付发送延时消息定时关闭订单
            return; // 将来走支付流程
        }

        // 4.先验余额并锁余额
        AccountLockVo accountLockVo = new AccountLockVo();
        Long userId = AuthContextHolder.getUserId();
        accountLockVo.setUserId(userId);
        accountLockVo.setOrderNo(tradeNo);
        accountLockVo.setAmount(orderInfoVo.getOrderAmount());
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (!CollectionUtils.isEmpty(orderDetailVoList)){
            accountLockVo.setContent(orderDetailVoList.get(0).getItemName());
        }
        Result<AccountLockResultVo> accountLockResultVoResult = this.userAccountFeignClient.checkLock(accountLockVo);
        if (accountLockResultVoResult == null || accountLockResultVoResult.getData() == null) {
            // 验余额锁余额失败
            throw new GuiguException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);
        }

//        int i = 1 / 0;

        try {
            // 5.保存订单
            this.saveOrder(orderInfoVo);

            // 6.扣减余额
            this.kafkaService.sendMsg(KafkaConstant.QUEUE_ACCOUNT_MINUS, tradeNo);
//        Result result = this.userAccountFeignClient.minus(tradeNo);
//        if (result == null){
//            throw new GuiguException(ResultCodeEnum.ACCOUNT_MINUSLOCK_ERROR);
//        }
        } catch (Exception e) {
            // 发送消息解锁余额
            this.kafkaService.sendMsg(KafkaConstant.QUEUE_ACCOUNT_UNLOCK, tradeNo);
            throw new RuntimeException(e);
        }
    }

    @Transactional
    @Override
    public void updateStatus(String orderNo, String expectStatus, String targetStatus) {
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        orderInfo.setOrderStatus(targetStatus);
        if (this.orderInfoMapper.update(orderInfo,
                new LambdaUpdateWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo).eq(OrderInfo::getOrderStatus, expectStatus)) == 1) {
            UserPaidRecordVo recordVo = new UserPaidRecordVo();
            recordVo.setOrderNo(orderNo);
            // 根据订单编号查询订单信息
            recordVo.setUserId(orderInfo.getUserId());
            recordVo.setItemType(orderInfo.getItemType());
            // 根据订单id查询订单详情
            List<OrderDetail> orderDetails = this.detailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId()));
            if (!CollectionUtils.isEmpty(orderDetails)){
                recordVo.setItemIdList(orderDetails.stream().map(OrderDetail::getItemId).collect(Collectors.toList()));
            }
            this.kafkaService.sendMsg(KafkaConstant.QUEUE_USER_PAY_RECORD, JSON.toJSONString(recordVo));
        }
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        // 查询订单
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        if (orderInfo == null) {
            return orderInfo;
        }

        // 查询订单详情
        List<OrderDetail> orderDetails = this.detailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId()));
        orderInfo.setOrderDetailList(orderDetails);

        // 查询订单减免信息
        List<OrderDerate> orderDerates = this.derateMapper.selectList(new LambdaQueryWrapper<OrderDerate>().eq(OrderDerate::getOrderId, orderInfo.getId()));
        orderInfo.setOrderDerateList(orderDerates);

        // 把支付状态转化成中文
        orderInfo.setOrderStatusName(getPayStatus(orderInfo.getOrderStatus()));

        // 把支付类型转化成中文
        orderInfo.setPayWayName(getPayWay(orderInfo.getPayWay()));

        return orderInfo;
    }

    @Override
    public Page<OrderInfo> findOrderInfoPage(Integer page, Integer limit) {

        // 分页查询订单
        Page<OrderInfo> orderInfoPage = this.page(new Page<OrderInfo>(page, limit),
                new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getUserId, AuthContextHolder.getUserId()).orderByDesc(OrderInfo::getId));
        if (orderInfoPage == null || CollectionUtils.isEmpty(orderInfoPage.getRecords())){
            return orderInfoPage;
        }

        // 遍历订单查询订单详情 减免信息 中文转换
        List<OrderInfo> orderInfos = orderInfoPage.getRecords();
        orderInfos.forEach(orderInfo -> {
            // 查询订单详情
            List<OrderDetail> orderDetails = this.detailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId()));
            orderInfo.setOrderDetailList(orderDetails);

            // 查询订单减免信息
            List<OrderDerate> orderDerates = this.derateMapper.selectList(new LambdaQueryWrapper<OrderDerate>().eq(OrderDerate::getOrderId, orderInfo.getId()));
            orderInfo.setOrderDerateList(orderDerates);

            // 把支付状态转化成中文
            orderInfo.setOrderStatusName(getPayStatus(orderInfo.getOrderStatus()));

            // 把支付类型转化成中文
            orderInfo.setPayWayName(getPayWay(orderInfo.getPayWay()));
        });

        return orderInfoPage;
    }

    private String getPayWay(String payWay){
        switch (payWay){
            case SystemConstant.ORDER_PAY_WAY_WEIXIN: return "微信支付";
            case SystemConstant.ORDER_PAY_WAY_ALIPAY: return "支付宝支付";
            case SystemConstant.ORDER_PAY_WAY_ACCOUNT: return "余额支付";
        }
        return null;
    }

    private String getPayStatus(String payStatus){
        switch (payStatus){
            case SystemConstant.ORDER_STATUS_UNPAID: return "未支付";
            case SystemConstant.ORDER_STATUS_PAID: return "已支付";
            case SystemConstant.ORDER_STATUS_CANCEL: return "已取消";
        }
        return null;
    }

    private void saveOrder(OrderInfoVo orderInfoVo){

        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (CollectionUtils.isEmpty(orderDetailVoList)){
            throw new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }

        // 1.保存订单信息order_info
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        // 设置userid
        Long userId = AuthContextHolder.getUserId();
        orderInfo.setUserId(userId);
        // 设置订单标题：取订单详情中的第一条记录的名称作为订单标题
        orderInfo.setOrderTitle(orderDetailVoList.get(0).getItemName());
        // 订单编号
        orderInfo.setOrderNo(orderInfoVo.getTradeNo());
        // 订单状态
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        this.save(orderInfo);
        // 获取订单id
        Long orderId = orderInfo.getId();

        // 2.保存订单详情信息order_detail
        orderDetailVoList.forEach(orderDetailVo -> {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(orderDetailVo, orderDetail);
            orderDetail.setOrderId(orderId); // 设置订单id
            this.detailMapper.insert(orderDetail);
        });

        // 3.保存订单减免信息order_derate
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)){
            orderDerateVoList.forEach(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderId);
                this.derateMapper.insert(orderDerate);
            });
        }

//        int i = 1/0;
    }
}
